package com.analysis.service.impl;

import java.util.List;

import com.analysis.common.FileUtil;
import com.analysis.model.MinMax;
import com.analysis.service.ZigzagService;


public class ZigzagServiceImpl implements ZigzagService {
	public int[] calZigzag(double[] in,int maxrecursion){
		int len = in.length;
		int[] result= new int[len];
		
		MinMax statistic = minMax(in,0,in.length-1);
		
		if(statistic.getMin()==-1&&statistic.getMax()==-1){
			return result;
		}else if (statistic.getMin() != -1 && statistic.getMax() == -1){
			result[0] = 1;
			result[len - 1] = 1;
			result[statistic.getMin()] = -1;
			zigzag(1, in, result, len, 0, statistic.getMin(), maxrecursion);
			zigzag(1, in, result, len, statistic.getMin(), len - 1, maxrecursion);
		}else if (statistic.getMin() == -1 && statistic.getMax() != -1){
			result[0] = -1;
			result[len - 1] = -1;
			result[statistic.getMax()] = 1;
			zigzag(1, in, result, len, 0, statistic.getMax(), maxrecursion);
			zigzag(1, in, result, len, statistic.getMax(), len - 1, maxrecursion);
		}else{
			if (statistic.getMin() < statistic.getMax()){
				result[0] = 1;
				result[len - 1] = -1;
				result[statistic.getMin()] = -1;
				result[statistic.getMax()] = 1;
				zigzag(1, in, result, len, 0, statistic.getMin(), maxrecursion);
				zigzag(1, in, result, len, statistic.getMin(), statistic.getMax(), maxrecursion);
				zigzag(1, in, result, len, statistic.getMax(), len - 1, maxrecursion);
			}else{
				result[0] = -1;
				result[len - 1] = 1;
				result[statistic.getMin()] = -1;
				result[statistic.getMax()] = 1;
				zigzag(1, in, result, len, 0, statistic.getMax(), maxrecursion);
				zigzag(1, in, result, len, statistic.getMax(), statistic.getMin(), maxrecursion);
				zigzag(1, in, result, len, statistic.getMin(), len - 1, maxrecursion);
			}
		}
		

		int[] mapped = new int[result.length];
		for(int i=0;i<result.length;i++){
			if(result[i]!= 0){
				mapped[i] = 1;
			}else{
				mapped[i] = 0;
			}
		}
		return mapped;
	
	}

	private void zigzag(int depth, double[] in, int[] extreme, int len, int startpos, int endpos, int maxrecursion){

		if (endpos - startpos < 3)
			return;

		if (depth == maxrecursion)
			return;
		MinMax statistic = minMax(in,startpos,endpos);

		if (statistic.getMin() == -1 && statistic.getMax() == -1){
			return;
		}else if (statistic.getMin() != -1 && statistic.getMax() == -1){
			extreme[statistic.getMin()] = -1;
			zigzag(depth + 1, in, extreme, len, startpos, statistic.getMin(), maxrecursion);
			zigzag(depth + 1, in, extreme, len, statistic.getMin(), endpos, maxrecursion);
		}else if (statistic.getMin() == -1 && statistic.getMax() != -1){
			extreme[statistic.getMax()] = 1;
			zigzag(depth + 1, in, extreme, len, startpos, statistic.getMax(), maxrecursion);
			zigzag(depth + 1, in, extreme, len, statistic.getMax(), endpos, maxrecursion);
		}else{
			if (statistic.getMin() < statistic.getMax()){
				extreme[statistic.getMin()] = -1;
				extreme[statistic.getMax()] = 1;
				zigzag(depth + 1, in, extreme, len, startpos, statistic.getMin(), maxrecursion);
				zigzag(depth + 1, in, extreme, len, statistic.getMin(), statistic.getMax(), maxrecursion);
				zigzag(depth + 1, in, extreme, len, statistic.getMax(), endpos, maxrecursion);
			}else{
				extreme[statistic.getMin()] = -1;
				extreme[statistic.getMax()] = 1;
				zigzag(depth + 1, in, extreme, len, startpos, statistic.getMax(), maxrecursion);
				zigzag(depth + 1, in, extreme, len, statistic.getMax(), statistic.getMin(), maxrecursion);
				zigzag(depth + 1, in, extreme, len, statistic.getMin(), endpos, maxrecursion);
			}
		}
	}
	

	private MinMax minMax(double[] data, int startPos, int endPos) {
		int intervalLength = endPos - startPos + 1;
		double k = (data[endPos] - data[startPos]) / intervalLength;

		double[] horizontal = new double[intervalLength];
		for (int i = startPos; i <= endPos; i++) {
			horizontal[i - startPos] = data[i] - (i - startPos) * k;
		}

		int iMin = startPos, iMax = endPos;
		double tempMin = horizontal[iMin - startPos], tempMax = horizontal[iMax - startPos];

		for (int i = startPos; i <= endPos; i++) {
			if (horizontal[i - startPos] < tempMin) {
				iMin = i;
				tempMin = horizontal[iMin - startPos];
			} else if (horizontal[i - startPos] > tempMax) {
				iMax = i;
				tempMax = horizontal[iMax - startPos];
			}
		}

		MinMax statistic = new MinMax();

		if (iMin != startPos && iMin != endPos) {
			statistic.setMin(iMin);
		}

		if (iMax != startPos && iMax != endPos) {
			statistic.setMax(iMax);
		}

		return statistic;
	}

	public void run() {
		List<String> closes =  FileUtil.readLines("./kline/input.txt");
		double[] in = new double[closes.size()];
		for(int i=0;i<closes.size();i++){
			in[i] = Double.valueOf(closes.get(i));
		}
		
		int maxrecursion = (int)(Math.pow((double)in.length / 15, 0.333));
		if (maxrecursion > 5)
			maxrecursion = 5;
		
		int[] result = calZigzag(in,maxrecursion);
		for(int i=0;i<result.length;i++){
			System.out.println(result[i]);
		}
		compare(result);
	}
	
	public void compare(int[] result){
		List<String> zigzagFile =  FileUtil.readLines("./kline/zigzag.txt");
		if(result.length!=zigzagFile.size()){
			throw new IllegalArgumentException("Size not match.");
		}
		for(int i=0;i<result.length;i++){
			String fromFile = zigzagFile.get(i);
			System.out.println(fromFile+" "+result[i]);
			if(result[i]!=Integer.valueOf(fromFile)){
				throw new IllegalArgumentException("Not match.");
			}
		}
	}

	public static void main(String[] args) {
		new ZigzagServiceImpl().run();
	}
}
